home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1996 #15
/
Monster Media Number 15 (Monster Media)(July 1996).ISO
/
prog_c
/
sw14d.zip
/
MOU105.ZIP
/
MOU.DOC
< prev
next >
Wrap
Text File
|
1991-09-25
|
23KB
|
537 lines
Turbo and Microsoft C Mouse Routines - Release 1.05
---------------------------------------------------
Thu 27-Jan-1991
CONTENTS
1. What do these routines do?
2. How it works.
3. Variable and definition reference.
4. Function reference.
5. The test program.
6. Disclaimer and other stuff.
7. Modification history.
1. What do these routines do?
-----------------------------
These routines will allow you to interface with the mouse driver in your
programs. It works with Microsoft compatible mouse drivers (i.e. Logitech,
PC Mouse, Dexxa, etc). The routines have the added feature of displaying a
'true' mouse cursor in text mode on an EGA or VGA by reprogramming the font
on the fly.
The routines consist of several functions used to initialize, draw the
cursor, and get mouse events (button presses).
These routines do not handle drawing the mouse cursor in graphics mode,
only text mode. If the routines detect the presence of an EGA/VGA adapter,
it will use the 'true' mouse cursor, if not it will use a simple block
cursor implemented by switch the foreground/background colors of the
position the cursor is.
The routines are distributed in a ZIP file with the following files:
MOU.DOC - This documentation file.
MOU.C - Turbo C/MSC source code.
MOU.H - Turbo C/MSC header file.
TEST.C - Turbo C/MSC test program.
MOU.PAS - Turbo Pascal unit.
PTEST.PAS - Turbo Pascal test program.
MAKEFILE - Makefile for creating TC/MSC versions.
TTEST.EXE - Turbo C test program.
MTEST.EXE - Microsoft C test program.
PTEST.EXE - Turbo Pascal test program.
2. How it works.
---------------
All character coordinates used by the mouse driver are zero based. I.e. in
80x25 text mode the range of values for x and y are 0-79 and 0-24. The
routines should work in all memory models.
The routines first check for the presence of a mouse driver, and if none is
present, they return without doing anything. It is safe to call the
routines such as MOUhide() and others even if a mouse is not installed,
they will simply return.
Once the presence of a Microsoft compatible mouse driver is verified, the
routine checks the presence of DESQview and an EGA/VGA. If an EGA/VGA is
in the system, and the program is not running under DESQview, the routines
will choose to use a 'true' cursor, otherwise a simple block cursor will be
used. A 'true' cursor is not used under DESQview because DESQview doesn't
really like having it's font changed on the fly by a program. The 'true'
mouse cursor would probably interfere with other programs running at the
same time.
The mouse driver does have a glitch that these routines have to work
around, that being that when in text mode, the mouse driver returns the
coordinates as multiples of 8 (i.e. 0, 8, 16, 24 ...). Since the 'true'
cursor has a pixel resolution, we need to get the mouse driver to return
coordinates in pixels (i.e. 0, 1, 2, 3 ...). To do this, we 'trick' the
mouse driver into thinking it is in graphics mode (where coordinates are
returned in pixels) by changing the current video mode. This is done by
placing a value of 6 in memory location 0x0040:0x0049, 6 being the number
for CGA 640x200 2 color graphics mode. We then tell the mouse driver to
initialize again (using mouse driver function 0), and the mouse driver
checks the video mode, sees that we are in graphics mode, and sets itself
up accordingly. We then restore the mode byte at 0x0040:0x0049 to it's
previous value. After this, the mouse driver returns all coordinates in
pixels. I had to hack out this fix on my own, I called Microsoft and got
nothing from them, but I remembered that when you are running the mouse
driver in graphics mode on a Hercules graphics adapter, you have to do this
'trick.' It worked in this case as well.
Next the initialization routine sets up the maximum x and y ranges for the
mouse cursor based on the dimensions of the video mode. Lastly it installs a
mouse function handler using mouse driver function 12 -- define handler.
The handler is installed for mouse movement, and left or right button
presses and releases.
The handler is defined in the function 'void far mousehandler(void)'. This
function is called by the mouse driver upon one of the events happening as
defined in the call to mouse driver function 12. The handler will
automatically update the mouse cursor, change the global variables mousex
and mousey to the character (not pixel) coordinates of the mouse. It also
checks for mouse events (button presses and releases) and stores them into
a buffer if an event happens. This event is later retrieved with a call to
MOUpreview() or MOUget().
The drawing of the mouse cursor on non EGA/VGA adapters is quite simple.
It reverses the foreground and background color of the character where the
mouse is located. This is the default text cursor that the mouse driver
uses itself.
On an EGA/VGA adapter, things get a little more complicated. A 3x3
character arrangement is used to draw the cursor. The function
plotegavgacursor() handles saving the 3x3 character array, restoring it
later, and drawing the 3x3 array of characters that is redefined. The
redefinition consists of reading the definitions of the characters,
preforming an AND and OR of the mouse cursor onto the existing definitions,
then copying those modified definitions to a new location. I copy to
characters 0xd0 to 0xd8. Then the characters 0xd0 to 0xd8 are placed in
the 3x3 grid where the mouse cursor is located, thereby drawing the cursor.
The mouse cursor is a simple array of dwords (32 bit unsigned long) that is
used to update the character definitions. The cursor can be changed from
the default one provided, as defined in the mouse driver documentation for
defining graphics cursors. It consists of two masks: the screen mask, and
the cursor mask. The screen mask is bitwise AND'ed to the existing character
definitions, then the cursor mask is bitwise OR'ed to the existing character
definitions.
The functions MOUshow(), MOUhide() and MOUconditionalhide() perform as
their counterpart functions provided by the mouse driver.
MOUconditionalhide() is a special function (that some 'clone' drivers
_don't_ have) that allows you to update a rectangular region on the screen
without disturbing the mouse (if it is not in the region). It is called
with the character coordinates of a rectangular region on the screen. If
the mouse is in that region, or if the mouse moves into that region, the
mouse cursor will automatically turn off. A call to MOUshow() cancels the
rectangular region. You can't make multiple calls to MOUconditionalhide()
between calls to MOUshow().
Various 'glitches' arise by using a 'true' mouse cursor. They are listed
as follows:
1. On the VGA adapter, standard text mode consists of 9 by 16 characters.
The character are not actually 9 bits wide, but 8. The VGA duplicates
the rightmost bit for the border characters (characters 176 to 218).
The 'true' cursor uses (rather redefines) characters 208 to 216 (0xd0
to 0xd8 hex), thereby having its rightmost bit duplicated. If another
set of characters is used, the cursor appears to have a 'gap' in the
middle of it. The problem lies in that if the cursor is moved over a
character that has some of its rightmost bit set, the rightmost bit
will be duplicated. Characters such as the lower case 'm' are
examples of this. It is much easier to see the effect of this than
explain it. Run the TEST program that comes with the routines and
place the cursor over a lower case m on the screen. You will notice
the effect. I can't see any way around this. This doesn't happen on
an EGA as the EGA uses 8 pixel width characters (not 9).
2. Since the 'true' mouse cursor is larger than one character, moving the
cursor into areas of the screen with different foreground colors will
cause the cursor to take on that color. If the cursor is at the
border of two different foreground colors, it will appear that the
cursor is in two colors. I got around this by always using the same
foreground color for all characters on the screen (i.e. WHITE) and
just using different background colors to show differences on the
screen.
3. DESQview doesn't like its font changed on the fly. It interferes with
the 'true' cursor to the point where it's dysfunctional. The mouse
routines will automatically detect DESQview and fall back to a normal
block cursor if running under DV.
4. Since the font is changed, characters 0xd0 to 0xd8 are not available
for use by the program. These characters are the IBM border
characters used to connect double line and single line boxes together.
I don't use these characters in my programs, and they aren't really
needed. If you need to have a single line join a double line graphics
character, just place them side by side. They won't actually 'join'
as it would by using a double to single line character, but they will
line up closely. I find it an acceptable loss to provide a 'true'
mouse cursor on the EGA/VGA.
For a description of how to change fonts on the EGA/VGA adapters, I highly
recommend the book by Richard Wilton, _Programmer's Guide to PC & PS/2
Video Systems_. An excellent book if you are doing any kind of video
programming. For a description of the mouse driver interface, I can
recommend Logitech's Mouse Programmer's Toolkit, Microsoft Press's Mouse
Reference Guide, and Ralf Brown's Interrupt List (updated periodically).
I initially learned the interface to the mouse driver from an article in PC
Magazine (I can't remember what issue), and I use Ralf Brown's Interrupt
List for reference now.
3. Variable and definition reference.
-------------------------------------
The following variables and definitions are included in MOU.H:
C: MOUINFOREC
Pascal: mouinforectype
This is the definition for the structure returned by the functions
MOUpreview() and MOUget(). It contains the following fields:
word buttonstat: bits in this field indicate what event occurred. See them
below.
int cx, cy: character coordinates of where this event occurred.
byte shiftshate: the status of the shift keys at the time of the event.
See definitions below.
---------------------------------------
C: MOUBUFFERSIZE
Pascal: MOUBUFFERSIZE
This is the size of the mouse buffer. The buffer is where mouse events are
held for the program until is retrieves them with MOUget().
---------------------------------------
C: MOUSEMOVE, LEFTBPRESS, LEFTBRELEASE, RIGHTBPRESS, RIGHTBRELEASE,
MIDBPRESS, MIDBRELEASE
Pascal: MOUSEMOVE, LEFTBPRESS, LEFTBRELEASE, RIGHTBPRESS, RIGHTBRELEASE,
MIDBPRESS, MIDBRELEASE
These defines are for the field buttonstat in the MOUINFOREC structure. By
checking the bits of buttonstat, you can find out what event occurred, for
example, "if (m.buttonstat & LEFTBPRESS)" will be true if the event was
caused by the press of the left mouse button.
---------------------------------------
C: LEFTBDOWN, RIGHTBDOWN
Pascal: LEFTBDOWN, RIGHTBDOWN
These defines are used for the value returned by the function
MOUbuttonstatus(). I.e. "if (MOUbuttonstatus() & LEFTBDOWN)" will be TRUE
if the left mouse button is currently down.
---------------------------------------
C: SHIFT_RIGHTSHIFT, SHIFT_LEFTSHIFT, SHIFT_SHIFT, SHIFT_CTRL, SHIFT_ALT,
SHIFT_SCROLLLOCK, SHIFT_NUMLOCK, SHIFT_CAPSLOCK, SHIFT_INS
Pascal: SHIFT_RIGHTSHIFT, SHIFT_LEFTSHIFT, SHIFT_SHIFT, SHIFT_CTRL, SHIFT_ALT,
SHIFT_SCROLLLOCK, SHIFT_NUMLOCK, SHIFT_CAPSLOCK, SHIFT_INS
These defines are for the shiftstate field in the MOUINFOREC structure. It
allows you to check for such things as shift-clicks. I.e.
"if (m.shiftstate & SHIFT_LEFTSHIFT)" will be TRUE if the left shift key
was held down during the mouse event. SHIFT_SHIFT is defined as both shift
keys.
---------------------------------------
C: word mousehidden;
Pascal: mousehidden : word;
This variable will be true (non-zero) if the mouse is currently hidden. It
is undefined if mouseinstalled is false. Don't write to this variable,
it's just provided for your reference.
---------------------------------------
C: boolean mouseinstalled;
Pascal: mouseinstalled : boolean;
This variable will be true (non-zero) if a mouse driver is installed and
operating and the mouse routines are active and reading the mouse and
drawing the cursor. If it is false, the mouse driver routines will not
operate, calling them will do nothing (but calling them is not harmful).
---------------------------------------
C: volatile int mousex, mousey;
Pascal mousex, mousey : integer;
These variables hold the current location of the mouse cursor. They are
updated by the mouse handler. Note that their value may changed at _any_
time. Don't depend on them being constant. If you need to reference them,
I recommend declaring a couple of variables to hold their values (i.e. int
x, y; x = mousex; y = mousey;) and using those instead of mousex and
mousey. Only reference mousex and mousey when you need to update the
position.
4. Function reference.
----------------------
C: void FAST MOUinit(void);
Pascal: procedure MOUinit;
This function initializes the mouse routines, checks for presence of the
mouse driver, DESQview and an EGA/VGA. What it does is described above in
"How does it work?".
---------------------------------------
C: void FAST MOUdeinit(void);
Pascal: procedure MOUdeinit;
This function will deinitialize the mouse routines. It will stop the mouse
driver from calling the handler, and erase the mouse cursor. You can call
MOUinit() if you wish to use the mouse driver routines again. You MUST call
this function before you quit your program. Failure to do so will most
likely cause your computer to crash next time the mouse is moved. If you
don't call it, the mouse driver still calls the mouse hander, even after
the program has quit.
---------------------------------------
C: void FAST MOUhide(void);
Pascal: procedure MOUhide;
This hides the mouse cursor. The mouse cursor must be hidden with this
function (or MOUconditionalhide() below) before doing any screen updating.
This prevents overwriting the mouse cursor. The preferred way to hide the
mouse is MOUconditionalhide(). But if you are clearing the screen, or
updating all of it at once, use this function. This function counts how
many times it has been called, i.e. if you call it twice, you have to call
MOUshow() twice to get the cursor back on the screen.
---------------------------------------
C: void FAST MOUconditionalhide(int x1, int y1, int x2, int y2);
Pascal: procedure MOUconditionalhide(x1, y1, x2, y2 : integer);
This function hides the mouse automatically if it is in, or is moved in,
the rectangular region defined by this function. If possible use this
function to hide the mouse, as if the mouse isn't near the area being
updated, it won't 'blink' like it would calling MOUhide(). The coordinates
are zero based and x1 must be <= x2 and y1 must be <= y2. Call MOUshow()
after you have finished updating the region you defined. If the mouse was
hidden, MOUshow() will turn it back on.
---------------------------------------
C: void FAST MOUshow(void);
Pascal: procedure MOUshow;
This turns on the mouse cursor after a previous call to MOUhide() or
MOUconditionalhide(). This function may be called as many times as you
like, once the cursor is not hidden, any other calls will have no effect.
---------------------------------------
C: boolean FAST MOUcheck(void);
Pascal: function MOUcheck : boolean;
This function returns true (non-zero) if there are events in the buffer, if
not it returns false (zero).
---------------------------------------
C: void FAST MOUpreview(MOUINFOREC *mouinforec);
Pascal: procedure MOUpreview(var mouinforec : mouinforectype);
This function passes the next event to the MOUINFOREC passed to it. It
does not remove the event from the buffer. If there are no events in the
buffer, the MOUINFOREC returned will have the current mouse position in the
cx and cy fields of the MOUINFOREC, the shiftstate field set to the current
state of the shift keys, and the buttonstat field blank (zero, or no
events).
---------------------------------------
C: void FAST MOUget(MOUINFOREC *mouinforec);
Pascal: procedure MOUget(var mouinforec : mouinforectype);
This function passes the next event to the MOUINFOREC passed to it. It
will remove the event from the buffer. If there are no events in the
buffer, the MOUINFOREC returned will have the current mouse position in the
cx and cy fields of the MOUINFOREC, the shiftstate field set to the current
state of the shift keys, and the buttonstat field blank (zero, or no
events).
---------------------------------------
C: word FAST MOUbuttonstatus(void);
Pascal: function MOUbuttonstatus : word;
This will return the current status of the mouse buttons. It can be
ANDed with LEFTBDOWN, MIDBDOWN or RIGHTBDOWN to see if either button is
currently being held down. This function could be used to detect
dragging of the mouse.
---------------------------------------
C: void FAST MOUsetpos(word x, word y);
Pascal: procedure MOUsetpos(x, y : integer);
Sets the current mouse position. Mouse will move to the new coordinates on
the call. Parameters are character coordinates, not pixel coordinates.
5. The test program.
--------------------
Included with the routines is a small test program that will allow you to
see the 'true' mouse cursor (if you have an EGA/VGA adapter). Included is
a makefile for NDMake and Turbo C/Microsoft C. The makefile defaults to
Turbo C, you have to make a simple edit for Microsoft C. If you don't have
a makefile, you can compile it like this:
tcc -ml test.c mou.c
or under MSC as:
cl /AL test.c mou.c
or under Turbo Pascal:
tpc ptest.pas
Note: with Turbo C, you will require to have TASM in your path as the
routines have inline assembler in them. MASM isn't required for MSC (MSC
has a built in assembler, though it's a bit dumb at times).
It's a simple program that will tell you the current mouse position and the
status of the mouse buttons.
The mouse routines will work in ALL EGA/VGA text modes. I've run it in
80x25 and 80x50 mode and the 'true' cursor will be drawn in both those
modes. My VGA supports a 132x60 mode as well, and the 'true' mouse cursor
works perfectly in that mode as well.
The C version of the test program requires ANSI.SYS to be installed.
6. Disclaimer and other stuff.
------------------------------
I originally started working on these routines when I first saw the new
version of Norton's Utilities (version 5.0). I was impressed with the
'true' mouse cursor it was drawing in text mode, and wanted to know if I
could write a set of routines to do the same thing.
In Jan. of '91, a discussion on the group comp.os.msdos.programmer about the
way Norton does the 'true' mouse cursor arose. I replied to a message by
Brian K. W. Hook who indicated that he doubted Norton changed the font on
the fly to implement a 'true' mouse cursor in text mode. He stated he was
'baffled' by the way that Norton did it. I stated that Norton did do it by
changing the font on the fly, and that I had written some routines to do it
as well.
Brian asked me for the routines, as well as a couple of other users, so I
cleaned them up, made them independent of my text window library (I've
written a library for text window routines that I use in my programs) and
otherwise prepared to unleash them on unsuspecting Usenet victims. :)
These routines also illustrate interfacing to mouse driver function 12,
which seems to be a common question on comp.os.msdos.programmer (How to I do
interface to the mouse driver?).
I'll supply support for these routines as my time permits, and I can be
reached by any of the following methods of communication:
Email: UUCP: {uunet,ubc-cs}!van-bc!rsoft!mindlink!a563
Internet/Usenet: Zoid@mindlink.bc.ca
Zoid@mindlink.bc.ca is preferred.
Mail: #801-9835 King George Hwy.
Surrey, BC Canada
V3T 5H6
Phone: 604-585-8844.
Duncan Murdoch converted the routines to Turbo Pascal 6.0 for me. He can
be reached at:
dmurdoch@watstat.waterloo.edu
I do hope you enjoy these routines, and have an 'edge' on the competition
by having a flashy 'true' cursor on the EGA/VGA. Wow!
DISCLAIMER
Dave Kirsch makes no warranty of any kind, either express or implied,
including but not limited to implied warranties of merchantability
and fitness for a particular purpose, with respect to this software
and accompanying documentation.
IN NO EVENT SHALL DAVE KIRSCH BE LIABLE FOR ANY DAMAGES (INCLUDING
DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF
BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) ARISING OUT OF THE
USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF DAVE KIRSCH HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
Programmers may incorporate any or all code into their programs,
giving proper credit within the source. Publication of the
source routines is permitted so long as proper credit is given
to Dave Kirsch.
Copyright (C) 1990, 1991 by Dave Kirsch.
7. Modification history.
------------------------
Date Version
91-10-25 1.05 Fixed the documentation a bit.
91-03-15 1.04 Added a function to set the current mouse position. From a
suggestion by Gary Tepel.
91-01-27 1.03 Added the Turbo Pascal version and cleaned up the code and
documentation. Fixed so it _does_ work under MSC 6.0.
91-01-17 1.02 Added support for the middle mouse button, from diffs sent
to me from acero@quads.uchicago.edu (Tony Acero).
91-01-10 1.01 Fixed bug when referencing POINTS in the mouse handler.
91-01-08 1.00 Initial release.
Planned enhancements:
1. It's currently untested with Turbo C++, can anyone verify it works with
it? It should.
2. Functions to redefine the mouse cursor on the fly.
3. Convert it for use with other C/C++ compilers (i.e. Zortech).
4. I've had a report or two of a 'grid' appearing with the cursor on Sigma
VGA cards. I want to investigate this.
5. Make it work on Hercules RAMFont.